/*
 * DebugGUI.java
 * 
 * Team Dovahkiin:
 * Major Bruno, Matthew Selfors
 * 
 * This class is a Graphical User Interface for our simulation of the SC-2.
 */

package phaseII;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import phaseIII.TextAreaOutputStream;

/**
 * This class is a Graphical User Interface for our simulation of the SC-2.
 * 
 * @author Major Bruno
 * @author Matthew Selfors
 * @version 1.0
 */
@SuppressWarnings("serial")
public class DebugGUI extends JFrame implements Observer {
	
	/**
	 * Panel that displays the memory.
	 */
	private JPanel mem_panel;
	
	/**
	 * Panel that displays the registers.
	 */
	private JPanel reg_panel;
	
	/**
	 * Panel that displays the CPU registers.
	 */
	private JPanel stats_panel;
	
	/**
	 * Panel that displays the options for the user.
	 */
	private JPanel options_panel;
	
	/**
	 * Panel that displays the console.
	 */
	private JPanel console_panel;
	
	/**
	 * TextField used for user input.
	 */
	private JTextField text_field;
	
	/**
	 * TextArea that displays the memory.
	 */
	private JTextArea mem_area;
	
	/**
	 * TextArea that displays the registers.
	 */
	private JTextArea reg_area;
	
	/**
	 * TextArea that displays the CPU registers.
	 */
	private JTextArea stats_area;
	
	/**
	 * TextArea that displays the options for the user.
	 */
	private JTextArea options_area;
	
	/**
	 * TextArea that displays the console.
	 */
	private JTextArea console_area;
	
	/**
	 * An instance of the DebugMonitor.
	 */
	protected DebugMonitor debug;
	
	/**
	 * An instance of the CPU.
	 */
	protected CPU cpu;
	
	/**
	 * String used to display Strings to the console.
	 */
	protected String console_string;
	
	/**
	 * Constructor, calls super and initializes the fields.
	 */
	public DebugGUI() {
		super();
		cpu = new CPU();
		debug = new DebugMonitor(cpu);
		console_string = "";
		
		setUpFrame();
		setUpPanel();
	}
	
	/**
	 * Private helper method used by the constructor.
	 * Sets up the frame used in the GUI.
	 */
	private void setUpFrame() {
		setTitle("SC-2 Simulator");
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setVisible(true);
		setResizable(false);
		getContentPane().setLayout(new GridBagLayout());
		setBackground(Color.BLACK);
	}
	
	/**
	 * Private helper method used by the constructor.
	 * Sets up each panel used in the GUI.
	 */
	private void setUpPanel() {
		GridBagConstraints mem_c = new GridBagConstraints();
		GridBagConstraints reg_c = new GridBagConstraints();
		GridBagConstraints stats_c = new GridBagConstraints();
		GridBagConstraints options_c = new GridBagConstraints();
		GridBagConstraints text_c = new GridBagConstraints();
		GridBagConstraints console_c = new GridBagConstraints();

		mem_panel = new JPanel(new BorderLayout());
		mem_c.fill = GridBagConstraints.HORIZONTAL;
		mem_c.gridx = 2;
		mem_c.gridy = 0;
		getContentPane().add(mem_panel, mem_c);

		reg_panel = new JPanel(new BorderLayout());
		reg_c.fill = GridBagConstraints.HORIZONTAL;
		reg_c.weightx = 1;
		reg_c.ipady = 16;
		reg_c.gridx = 0;
		reg_c.gridy = 0;
		getContentPane().add(reg_panel, reg_c);

		stats_panel = new JPanel(new BorderLayout());
		stats_c.fill = GridBagConstraints.HORIZONTAL;
		stats_c.gridy = 1;
		stats_c.gridwidth = 3;
		getContentPane().add(stats_panel, stats_c);
		
		options_panel = new JPanel(new BorderLayout());
		options_c.fill = GridBagConstraints.HORIZONTAL;
		options_c.gridy = 2;
		options_c.gridwidth = 3;
		options_c.gridheight = 2;
		getContentPane().add(options_panel, options_c);
		
		text_field = new JTextField(5);
		text_c.fill = GridBagConstraints.HORIZONTAL;
		text_c.gridy = 4;
		text_c.gridwidth = 3;
		getContentPane().add(text_field, text_c);
		text_field.addActionListener(new InputListener());
		text_field.requestFocusInWindow();
		
		console_panel = new JPanel(new BorderLayout());
		console_c.fill = GridBagConstraints.HORIZONTAL;
		console_c.gridy = 5;
		console_c.weighty = 8;
		console_c.gridwidth = 3;
		getContentPane().add(console_panel, console_c);
		
		mem_area = new JTextArea(10, 18);
		reg_area = new JTextArea(10, 17);
		stats_area = new JTextArea(2, 32);
		options_area = new JTextArea(1, 32);
		console_area = new JTextArea(6, 32);
		
		mem_area.setBackground(Color.BLACK);
		mem_area.setForeground(Color.GREEN);
		reg_area.setBackground(Color.BLACK);
		reg_area.setForeground(Color.GREEN);
		stats_area.setBackground(Color.BLACK);
		stats_area.setForeground(Color.GREEN);
		options_area.setBackground(Color.BLACK);
		options_area.setForeground(Color.GREEN);
		text_field.setBackground(Color.BLACK);
		text_field.setForeground(Color.green);
		console_area.setBackground(Color.BLACK);
		console_area.setForeground(Color.GREEN);
		
		mem_area.setText(debug.showMemeory());
		mem_area.setEditable(false);
		mem_panel.add(mem_area);
		reg_area.setText(debug.showRegisters());
		reg_area.setEditable(false);
		reg_panel.add(reg_area);
		stats_area.setText(debug.cpu.cpuToString());
		stats_area.setEditable(false);
		stats_panel.add(stats_area);
		options_area.setText("\n1) Load  2) Run  3) Step  4) Quit");
		options_area.setEditable(false);
		options_panel.add(options_area);
		console_area.setEditable(false);
		console_panel.add(console_area);
		console_panel.add(new JScrollPane(console_area));
		
		TextAreaOutputStream taos = null;
		try {
			taos = new TextAreaOutputStream(console_area, 60);
		} catch (IOException e) {
			e.printStackTrace();
		}
        PrintStream ps = new PrintStream(taos);
        System.setOut(ps);
        System.setErr(ps);

		pack();
	}
	
	/**
	 * Part of the Observer interface, used
	 * to update the GUI to display output.
	 */
	@Override
	public void update(final Observable obs, final Object obj) {
		mem_area.setText(debug.showMemeory());
		reg_area.setText(debug.showRegisters());
		stats_area.setText(debug.cpu.cpuToString());
		if (cpu.instruction == 11000 && cpu.modifier == 1) {
			if (console_string.length() == 0) {
				console_string += cpu.getPort6();
			} else {
				console_string += "\n";
				console_string += cpu.getPort6();
			}
			console_area.setText(console_string);
//			console_area.append("\n");
		}
	}

	/**
	 * Private class used to listen for actions.
	 * 
	 * @author Major Bruno
	 * @author Matthew Selfors
	 * @version 1.0
	 */
	private class InputListener implements ActionListener {
		
		/**
		 * Performs an action based on the event received.
		 * 
		 * @param event the event that triggers an action.
		 */
		@Override
		public void actionPerformed(final ActionEvent event) {
			int command = 0;
			boolean isInt;
			try {
				command = Integer.parseInt(event.getActionCommand());
				isInt = true;
			} catch (Exception e) {
				isInt = false;
			}
			
			text_field.setText("");
			
			if (isInt) {
				if (command == 1) {
					try {
						debug.loadProgram();
					} catch (Exception e) {
						System.out.println("Error: " + e.getMessage());
					}
				} else if (command == 2) {
					debug.runProgram();
				} else if (command == 3) {
					debug.stepProgram();
				} else if (command == 4) {
					System.exit(0);
				}
			}
		}
	}
	
	/**
	 * Main method used to start the program.
	 * 
	 * @param args used for any command line arguments.
	 */
	public static void main(String[] args) {
		DebugGUI dg = new DebugGUI();
		dg.debug.addObserver(dg);
	}
}
